package com.tanjie.blackbean.system.admin.service.impl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.lang.tree.Tree;
import cn.hutool.core.lang.tree.TreeUtil;
import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.conditions.query.LambdaQueryChainWrapper;
import com.baomidou.mybatisplus.extension.conditions.update.LambdaUpdateChainWrapper;
import com.tanjie.blackbean.mybatis.query.Condition;
import com.tanjie.blackbean.system.admin.dao.OrgDaoService;
import com.tanjie.blackbean.system.admin.dao.OrgMapper;
import com.tanjie.blackbean.system.admin.model.org.OrgDTO;
import com.tanjie.blackbean.system.admin.model.org.OrgPO;
import com.tanjie.blackbean.system.admin.model.org.OrgQuery;
import com.tanjie.blackbean.system.admin.model.org.OrgVO;
import com.tanjie.blackbean.system.admin.service.IOrgService;
import com.tanjie.blackbean.pojo.exception.BizException;
import com.tanjie.blackbean.pojo.response.BizErrorCode;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import java.util.ArrayList;
import java.util.List;

import static com.tanjie.blackbean.pojo.system.SystemConstant.TREE_ROOT_ID;

/**
 * 组织机构
 *
 * @author tanjie
 * @since 2022-04-19
 */
@Slf4j
@Service
public class OrgServiceImpl implements IOrgService {

    @Resource
    OrgMapper orgMapper;

    @Resource
    OrgDaoService orgDaoService;

    @Override
    public OrgPO create(OrgDTO dto) {
        String name = dto.getName();
        this.verifyNameRepeat(name, null);
        OrgPO createOne = BeanUtil.copyProperties(dto, OrgPO.class);
        String parentId = dto.getParentId();
        if (StrUtil.isBlank(parentId)) {
            createOne.setParentId(TREE_ROOT_ID);
            createOne.setLayer(1);
        } else {
            OrgPO existParent = orgMapper.selectById(parentId);
            if (existParent == null) {
                throw new BizException("父级id在系统中不存在");
            }
            createOne.setLayer(existParent.getLayer() + 1);
        }
        orgMapper.insert(createOne);
        return createOne;
    }

    @Transactional(rollbackFor = Exception.class)
    @Override
    public void update(OrgDTO dto) {
        String id = dto.getId();
        OrgPO existOne = getByIdThr(id);
        // 修改了name
        String modifyName = dto.getName();
        String existName = existOne.getName();
        if (!existName.equals(modifyName)) {
            verifyNameRepeat(modifyName, id);
        }
        OrgPO updateOne = BeanUtil.copyProperties(dto, OrgPO.class);
        // 更换了父级
        String modifyParentId = dto.getParentId();
        String existParentId = existOne.getParentId();
        if (!existParentId.equals(modifyParentId)) {
            if (StrUtil.isBlank(modifyParentId)) {
                updateOne.setParentId(TREE_ROOT_ID);
                updateOne.setLayer(1);
                updateLayer(id, 1);
            } else {
                if (modifyParentId.equals(id)) {
                    throw new BizException("上级不可以是自己");
                }
                OrgPO parentOrg = orgMapper.selectById(modifyParentId);
                if (parentOrg == null) {
                    throw new BizException("父级id在系统中不存在");
                }
                // 递归遍历所有子级，不可以是自己的子级
                List<String> equalList = new ArrayList<>();
                this.recursionVerify(id, modifyParentId, equalList);
                if (equalList.size() > 0) {
                    throw new BizException("父级不可以选择自己的子级");
                }
                // 递归更新所有子级的layer字段
                Integer newLayer = parentOrg.getLayer() + 1;
                updateOne.setLayer(newLayer);
                this.updateLayer(id, newLayer);
            }
        }
        orgMapper.updateById(updateOne);
    }

    @Override
    public void delete(String id) {
        OrgPO existOne = getByIdThr(id);
        Long count = new LambdaQueryChainWrapper<>(orgMapper).eq(OrgPO::getParentId, id).count();
        if (count > 0) {
            throw new BizException("当前组织机构:{}中有{}个子级，请先删除所有子级。", existOne.getName(), count);
        }
        orgMapper.deleteById(id);
    }

    @Override
    public OrgVO detail(String id) {
        return BeanUtil.copyProperties(getByIdThr(id), OrgVO.class);
    }

    @Override
    public OrgPO getByIdThr(String id) {
        if (StrUtil.isBlank(id)) {
            throw new BizException(BizErrorCode.ID_REQUIRE_NOT_BLANK);
        }
        OrgPO existOne = orgMapper.selectById(id);
        if (existOne == null) {
            throw new BizException(BizErrorCode.ID_NOT_EXIST);
        }
        return existOne;
    }

    @Override
    public List<OrgVO> queryList(OrgQuery dto) {
        QueryWrapper<OrgPO> queryWrapper = getQueryWrapper(dto);
        List<OrgPO> list = orgMapper.selectList(queryWrapper);
        return BeanUtil.copyToList(list, OrgVO.class);
    }

    @Override
    public List<Tree<String>> queryTree() {
        List<OrgPO> orgList = new ArrayList<>();
        recursionQuery(TREE_ROOT_ID, orgList);
        return createTrees(orgList, TREE_ROOT_ID);
    }

    @Override
    public List<OrgVO> lazyTree(String parentId) {
        if (TREE_ROOT_ID.equals(parentId)) {
            return getChildren(TREE_ROOT_ID);
        }
        // 传入父级id 查询子级
        OrgPO existParentOrg = orgMapper.selectById(parentId);
        if (existParentOrg == null) {
            throw new BizException("父级id:{}在系统中不存在", parentId);
        }
        List<OrgVO> children = getChildren(parentId);
        if (children != null) return children;
        return new ArrayList<>();
    }

    @Override
    public void checkOrgExist(String id) {
        if (new LambdaQueryChainWrapper<>(orgMapper).eq(OrgPO::getId, id).count() == 0) {
            throw new BizException("组织机构id:{}在系统中不存在", id);
        }
    }


    // =================================================================================================================

    private QueryWrapper<OrgPO> getQueryWrapper(OrgQuery dto) {
        QueryWrapper<OrgPO> queryWrapper = null;
        if (dto != null) {
            queryWrapper = Condition.getQueryWrapper(BeanUtil.copyProperties(dto, OrgPO.class));
        }
        return queryWrapper;
    }

    /**
     * 查询所有子级
     *
     * @param parentId 父级id
     * @return 所有子级
     */
    private List<OrgVO> getChildren(String parentId) {
        List<OrgPO> children = new LambdaQueryChainWrapper<>(orgMapper)
                .eq(OrgPO::getParentId, parentId)
                .orderBy(true, true, OrgPO::getSort)
                .list();
        if (CollectionUtil.isNotEmpty(children)) {
            return BeanUtil.copyToList(children, OrgVO.class);
        }
        return null;
    }

    /**
     * 构建树
     *
     * @param allList  对象集合
     * @param parentId 根节点id
     * @return 树的集合
     */
    private List<Tree<String>> createTrees(List<? extends OrgPO> allList, String parentId) {
        return TreeUtil.build(allList, parentId, (po, treeNode) -> {
            treeNode.setId(po.getId());
            treeNode.setParentId(po.getParentId());
            treeNode.setName(po.getName());
            treeNode.setWeight(po.getSort());
            treeNode.putExtra("fullName", po.getFullName());
            treeNode.putExtra("layer", po.getLayer());
            treeNode.putExtra("remark", po.getRemark());
        });
    }

    /**
     * 组织迁移时，递归修改其layer层级字段
     *
     * @param parentId 父级id
     * @param layer    layer层数
     */
    private void updateLayer(String parentId, Integer layer) {
        // 查询子级集合
        List<OrgPO> childrenList = new LambdaQueryChainWrapper<>(orgMapper)
                .eq(OrgPO::getParentId, parentId)
                .list();
        // 查询到子级就更新
        if (CollectionUtil.isNotEmpty(childrenList)) {
            for (OrgPO one : childrenList) {
                String childId = one.getId();
                // 执行更新sql
                new LambdaUpdateChainWrapper<>(orgMapper)
                        .eq(OrgPO::getId, childId)
                        .set(OrgPO::getLayer, layer + 1)
                        .update();
                this.updateLayer(childId, layer + 1);
            }
        }
    }

    /**
     * 更新时，变更的父级id不能是自己的子级
     *
     * @param parentId  父级id
     * @param targetId  当前被修改的组织机构
     * @param equalList 符合判断条件的id数组
     */
    private void recursionVerify(String parentId, String targetId, List<String> equalList) {
        List<OrgPO> childrenList = new LambdaQueryChainWrapper<>(orgMapper)
                .eq(OrgPO::getParentId, parentId)
                .list();
        if (CollectionUtil.isEmpty(childrenList)) {
            return;
        }
        for (OrgPO po : childrenList) {
            String id = po.getId();
            if (id.equals(targetId)) {
                equalList.add(id);
            }
            this.recursionVerify(id, targetId, equalList);
        }
    }

    /**
     * 递归查询子树
     *
     * @param id      父级id
     * @param allList 收集容器，查询到数据就往里面放
     */
    private void recursionQuery(String id, List<OrgPO> allList) {
        List<OrgPO> list = new LambdaQueryChainWrapper<>(orgMapper)
                .eq(OrgPO::getParentId, id)
                .list();
        if (CollectionUtil.isEmpty(list)) {
            return;
        }
        allList.addAll(list);
        list.forEach(one -> this.recursionQuery(one.getId(), allList));
    }

    private void verifyNameRepeat(String name, String existId) {
        Long count = new LambdaQueryChainWrapper<>(orgMapper)
                .ne(OrgPO::getId, existId)
                .eq(OrgPO::getName, name)
                .count();
        if (count > 0) {
            throw new BizException("组织机构名称{}在系统中已存在", name);
        }
    }
}
